STM32实验

您所在的位置:网站首页 stm32 pwm输出引脚 STM32实验

STM32实验

2023-06-11 05:20| 来源: 网络整理| 查看: 265

一般一个STM32只有2个DAC输出通道,如果需要多路DAC输出,可以选择外扩DAC,但成本回相当高。于是在一些精度要求不高的场合,我们采用定时器输出PWM和RC滤波器模拟DAC来代替外扩DAC。

PWM占空比可由以下式子计算出:p = n / N (n是on的时间,即带宽,N是周期)

PWM周期是由ARR决定的,PWM占空比是由CCRx决定。ARR是自动重装载寄存器的数值,即定时器的锯齿波的最大值,CCRx是捕获/比较寄存器x的数值,是进行比较器comparator的正极电压。

于是我们知道,DAC输出电压为 = DORx / 4096 * Vref。对于分辨率 = log2 (N),比如N = 256,分辨率为8位。因为定时器的时钟频率往往更高,所以更容易获得更高的分辨率。本实验也以8位为例。

本实验的要求如下:要求一次谐波对输出电压影响不要超过一个位的精度,也就是3.3 / 256 = 0.01289V。假设Vh为3.3V,Vl为0V,这里的一次谐波的最大值为2 * 3.3 / pi = 2.1V。RC滤波电路要求是提供至少 -20lg(2.0 / 0.01289) = -44dB的衰减。截止频率要求为当定时器计数频率为72MHz,PWM DAC频率为8位时,PWM频率为72M / 256 = 281.25kHz,如果是一阶RC滤波,则要求截止频率为1.77kHz,如果是二阶RC滤波,则要求截止频率为22.34kHz。

对二阶RC滤波器来说,频率计算公式为f = (1 / (2 * pi)) *RC

接下来我们编写实验代码:

首先我们编写函数代码dac_pwm.c:

#include "dac_pwm.h" #include "./BSP/TIMER/gtim.h" TIM_HandleTypeDef g_timx_pwm_chy_handle; void dac_pwm_init(uint16_t arr, uint16_t psc){ TIM_OC_InitTypeDef timx_oc_pwm_chy; g_timx_pwm_chy_handle.Instance = TIM1; g_timx_pwm_chy_handel.Init.Prescaler = psc; g_timx_pwm_chy_handle.Init.Period = arr; g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数模式 g_timx_pwm_chy_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle); timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;//选择PWM1模式 timx_oc_pwm_chy.Pulse = 0;//设置占空比的比较值 timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_HIGH;//输出极性:低极性 HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_1); } void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim){ if(htim->Instance == TIM1){ GPIO_InitTypeDef gpio_init_struct; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_TIM1_CLK_ENABLE(); gpio_init_struct.Pin = GPIO_PIN_8; gpio_init_struct.Mode = GPIO_MODE_AF_PP; gpio_init_struct.Pull = GPIO_PULLUP; gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &gpio_init_struct); __HAL_RCC_AFIO_CLK_ENABLE(); __HAL_AFIO_REMAP_TIM3_PARTIAL(); } } void dac_pwm_set_voltage(uint16_t vol){ float temp = vol; temp /= 1000; temp = temp * 256 / 3.3; __HAL_TIM_SET_COMPARE(& timx_pwm_chy_handle, TIM_CHANNEL_1, temp); }

接下来再编写函数头文件dac_pwm.h:

#ifndef __DAC_PWM_H #define __DAC_PWM_H #include "./SYSTEM/sys/sys.h" extern TIM_HandleTypeDef g_timx_pwm_chy_handle; void dac_pwm_init(uint16_t arr, uint16_t psc); void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim); void dac_pwm_set_voltage(uint16_t vol); #endif

最后编写主函数代码main.c:

#include "./SYSTEM/delay/delay.h" #include "./SYSTEM/usart/usart.h" #include "./BSP/LED/led.h" #include "./BSP/GTIM/gtim.h" #include "./BSP/DAC/dac_pwm.h" int main(void){ uint16_t adcx = 0; float temp = 0; uint16_t t = 0; HAL_Init(); sys_stm32_clock_init(RCC_PLL_MUL9); delay_init(72); led_init(); lcd_init(); dac_init(); adc_init(); dac_pwm_init(256 - 1, 0); dac_pwm_set_voltage(3300); lcd_show_string(30, 50, 200, 16, 16, "STM32F103", RED); lcd_show_string(30, 70, 200, 16, 16, "DAC TEST", RED); lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED); lcd_show_string(30, 110, 200, 16, 16, "WK_UP:+ KEY1:-", RED); while (1) { adcx = adc_get_result(); lcd_show_xnum(134, 110, adcx, 5, 16, 0, BLUE); temp = (float)adcx * (3.3 / 4096); adcx = temp; lcd_show_xnum(134, 130, adcx, 1, 16, 0, BLUE); temp -= adcx; temp *= 1000; lcd_show_xnum(150, 110, temp, 3, 16, 0x80, BLUE); LED0_TOGGLE(); /* LED0闪烁 */ delay_ms(100); } }

到这里我们的实验代码就编写完毕了。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3